﻿using UnityEngine;
using UnityEngine.UI;

namespace UnityX
{
    internal class NotificationPanel : MonoBehaviour
    {
        internal class TipsObject
        {
            public GameObject gameObject;
            public RectTransform rectTransform;
            public ImageExtrude backgroundImage;
            public ImageCircle iconImage;
            public Text text;
            public float showPosition;
            public float endTime;
        }

        internal int maxShowCount = 4;
        internal float topDistanceHeightPercentage = 6;
        private float topDistance = 40;
        private float lineHeight = 50;
        private float totalLineHeight = 55;
        private int indexBegin = 0;
        private int indexEnd = 0;
        private float animationSpeed = 100;

        private TipsObject[] tipObjects;
        private Texture2D backgroundImage;
        private Font font;

        protected void Awake()
        {
            Create();
            SetSize();
        }
        protected void OnRectTransformDimensionsChange()
        {
            SetSize();
        }
        internal void Create()
        {
#if UNITY_2022_3_OR_NEWER
            font = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
#else
            font = Resources.GetBuiltinResource<Font>("Arial.ttf");
#endif
            backgroundImage = Resources.Load<Texture2D>("UnityX/Circle");
            tipObjects = new TipsObject[maxShowCount];
            for (int i = 0; i < tipObjects.Length; i++)
            {
                TipsObject tipObject = new TipsObject();

                tipObject.gameObject = new GameObject("_X_Tips_X_");
                tipObject.gameObject.transform.SetParent(transform, false);
                tipObject.backgroundImage = tipObject.gameObject.AddComponent<ImageExtrude>();
                tipObject.backgroundImage.sizeLeftType = ImageExtrude.SizeType.基于高度;
                tipObject.backgroundImage.sizeRightType = ImageExtrude.SizeType.基于高度;
                tipObject.backgroundImage.texture = backgroundImage;
                tipObject.rectTransform = tipObject.gameObject.GetComponent<RectTransform>();
                tipObject.rectTransform.anchorMin = new Vector2(0.5f, 1);
                tipObject.rectTransform.anchorMax = new Vector2(0.5f, 1);

                GameObject iconObject = new GameObject("_X_Icon_X_");
                iconObject.transform.SetParent(tipObject.gameObject.transform, false);
                tipObject.iconImage = iconObject.AddComponent<ImageCircle>();
                iconObject.AddComponent<LayoutRectTransform>()
                    .Set(LayoutRectTransform.AnchorType.中左
                    , 0.1f, LayoutRectTransform.PositionSizeType.基于父亲高度, 0, LayoutRectTransform.PositionSizeType.固定值
                    , 0.8f, LayoutRectTransform.WidthSizeType.基于父亲高度, 1, LayoutRectTransform.HeightSizeType.基于自己宽度);

                GameObject textObject = new GameObject("_X_Text_X_");
                textObject.transform.SetParent(tipObject.gameObject.transform, false);
                tipObject.text = textObject.AddComponent<Text>();
                tipObject.text.font = font;
                tipObject.text.alignment = TextAnchor.MiddleLeft;
                tipObject.text.alignByGeometry = true;
                tipObject.text.supportRichText = true;
                tipObject.text.raycastTarget = false;
                textObject.AddComponent<LayoutRectTransform>()
                    .Set(LayoutRectTransform.AnchorType.中左
                    , 1, LayoutRectTransform.PositionSizeType.基于父亲高度, 0, LayoutRectTransform.PositionSizeType.固定值
                    , 1, LayoutRectTransform.WidthSizeType.基于父亲宽度, 1, LayoutRectTransform.HeightSizeType.基于父亲高度);

                tipObject.gameObject.SetActive(false);
                tipObjects[i] = tipObject;
            }
        }
        internal void SetSize()
        {
            topDistance = Screen.height * (topDistanceHeightPercentage / 100.0f);
            topDistance = ((int)topDistance & 1) + (int)topDistance;//变整数和偶数
            lineHeight = ((Screen.width < Screen.height ? Screen.width : Screen.height) / 50.0f) + (Screen.dpi / 10.0f) + 10.0f;
            lineHeight = ((int)lineHeight & 1) + (int)lineHeight;//变整数和偶数
            totalLineHeight = lineHeight + (lineHeight / 10);
            totalLineHeight = ((int)totalLineHeight & 1) + (int)totalLineHeight;//变整数和偶数
            animationSpeed = lineHeight * 5;
            for (int i = 0; i < tipObjects.Length; i++)
            {
                tipObjects[i].text.fontSize = (int)(lineHeight / 2);
                tipObjects[i].rectTransform.sizeDelta = new Vector2(1000, lineHeight);
            }
            for (int i = indexBegin; i < indexEnd; i++)
            {
                TipsObject tipsObject = tipObjects[i % tipObjects.Length];
                tipsObject.rectTransform.sizeDelta = new Vector2(tipsObject.text.preferredWidth + (lineHeight * 1.5f), lineHeight);
                tipsObject.showPosition = -(totalLineHeight * (indexEnd - i - 1) + topDistance + (lineHeight / 2));
            }
        }
        public void Add(string content, NotificationStyle style, float duration)
        {
            // 位置计算
            float beginShowPosition = lineHeight / 2;
            if (indexBegin < indexEnd)
            {
                // 超出最大显示数量
                if (indexEnd - indexBegin >= tipObjects.Length)
                {
                    indexBegin++;
                }

                // 下移已经在屏幕上显示的消息的最终显示位置
                for (int i = indexBegin; i < indexEnd; i++)
                {
                    tipObjects[i % tipObjects.Length].showPosition -= totalLineHeight;
                }
                // 全部消息全部都在屏幕外，下移位置
                if (tipObjects[indexBegin % tipObjects.Length].rectTransform.anchoredPosition.y > totalLineHeight)
                {
                    for (int i = indexBegin; i < indexEnd; i++)
                    {
                        tipObjects[i % tipObjects.Length].rectTransform.anchoredPosition -= new Vector2(0, totalLineHeight);
                    }
                }

                beginShowPosition = tipObjects[(indexEnd - 1) % tipObjects.Length].rectTransform.anchoredPosition.y + totalLineHeight;
                if (beginShowPosition < lineHeight / 2)
                {
                    beginShowPosition = lineHeight / 2;
                }
            }
            else
            {
                gameObject.SetActive(true);
            }

            TipsObject tipsObject = tipObjects[indexEnd % tipObjects.Length];
            tipsObject.gameObject.SetActive(true);
            tipsObject.gameObject.transform.localScale = Vector3.one;
            tipsObject.backgroundImage.color = style.backgroundColor;
            tipsObject.iconImage.texture = style.iconTexture;
            tipsObject.iconImage.color = style.iconColor;
            tipsObject.text.color = style.textColor;
            tipsObject.text.text = content;
            tipsObject.rectTransform.sizeDelta = new Vector2(tipsObject.text.preferredWidth + (lineHeight * 1.5f), lineHeight);
            tipsObject.rectTransform.anchoredPosition = new Vector2(0, beginShowPosition);
            tipsObject.showPosition = -(topDistance + (lineHeight / 2));
            tipsObject.endTime = Time.time + duration;

            indexEnd++;
        }
        public void Clear()
        {
            for (int i = 0; i < tipObjects.Length; i++)
            {
                tipObjects[i].gameObject.SetActive(false);
            }
            gameObject.SetActive(false);
            indexBegin = 0;
            indexEnd = 0;
        }
        protected void Update()
        {
            for (int i = indexBegin; i < indexEnd; i++)
            {
                TipsObject tipsObject = tipObjects[i % tipObjects.Length];
                tipsObject.rectTransform.anchoredPosition -= new Vector2(0, 1) * (Time.deltaTime * animationSpeed);
                if (tipsObject.rectTransform.anchoredPosition.y < tipsObject.showPosition)
                {
                    tipsObject.rectTransform.anchoredPosition = new Vector2(0, tipsObject.showPosition);
                }
                if (indexBegin == i)
                {
                    if (Time.time > tipsObject.endTime)
                    {
                        tipsObject.rectTransform.localScale -= Vector3.one * Time.deltaTime * ((1 - tipsObject.rectTransform.localScale.x) * 4 + 0.2f);
                        if (tipsObject.rectTransform.localScale.x <= 0.01f)
                        {
                            tipsObject.gameObject.SetActive(false);
                            indexBegin++;
                            if (indexBegin >= indexEnd)
                            {
                                gameObject.SetActive(false);
                            }
                        }
                    }
                }
            }
        }
    }
}